package com.twilight.SofaStream;

import java.io.InputStream;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.util.List;

import com.twilight.SofaStream.R;

import android.app.Dialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.text.Html;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.net.Uri;
import android.net.Uri.Builder;
import android.content.DialogInterface;


public class EpisodeList extends ListActivity {

	private View currentlyPlaying;
	private TextView currentlyPlayingText;
	private ImageButton currentPlay, currentPause;
	private IPlayerService mPlayerService;
	private IDownloadService mDownloadService;
	RSSAdapter mAdapter;
	ListView mListView;
	
    
	IPlayerServiceCallback mPlayerUpdateCallback = new IPlayerServiceCallback.Stub() {
		public void update(int type, int value)  {
			mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(4, type, value));
		}
	};
	ServiceConnection mPlayerConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder service) {
			mPlayerService = IPlayerService.Stub.asInterface(service);
            try {
            	mPlayerService.registerCallback(mPlayerUpdateCallback);
				//If something's playing, show quick access gizmo
				showCurrentlyPlaying();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		public void onServiceDisconnected(ComponentName className) {
			try {
				mPlayerService.unregisterCallback(mPlayerUpdateCallback);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			mPlayerService = null;
		}
	};
	IDownloadServiceCallback mDownloadUpdateCallback = new IDownloadServiceCallback.Stub() {
		public void update(int type, long id, int progress)  {
			mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(5, type, progress, id));
		}
	};
	ServiceConnection mDownloadConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder service) {
            mDownloadService = IDownloadService.Stub.asInterface(service);
	            try {
					mDownloadService.registerCallback(mDownloadUpdateCallback);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
		public void onServiceDisconnected(ComponentName className) {
			try {
				mDownloadService.unregisterCallback(mDownloadUpdateCallback);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            mDownloadService = null;
		}
	};

	private void showCurrentlyPlaying() {
		try {
			if (mPlayerService.isActive()) {
				currentlyPlaying.setVisibility(View.VISIBLE);
				currentlyPlayingText.setText("Playing: " + mPlayerService.getTitle());
				if (mPlayerService.isPlaying()) {
					currentPlay.setVisibility(View.GONE);
					currentPause.setVisibility(View.VISIBLE);
				} else {
					currentPlay.setVisibility(View.VISIBLE);
					currentPause.setVisibility(View.GONE);
				}
			} else {
				currentlyPlaying.setVisibility(View.GONE);
			}
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.episode_list);
        super.onCreate(savedInstanceState);
        this.setTitle("Episode List");
        mAdapter = new RSSAdapter(this);
        setListAdapter(mAdapter);
        mListView = getListView();
        mListView.setOnScrollListener(mAdapter);
		currentlyPlaying = findViewById(R.id.CurrentlyPlaying);
		TextView missingText = ((TextView)findViewById(R.id.MissingText));
		currentPlay = (ImageButton) findViewById(R.id.listplay);
		currentPlay.setOnClickListener(new ImageButton.OnClickListener() {
			public void onClick(View v) {
				try {
					mPlayerService.startTrack();
					showCurrentlyPlaying();
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		currentPause = (ImageButton) findViewById(R.id.listpause);
		currentPause.setOnClickListener(new ImageButton.OnClickListener() {
			public void onClick(View v) {
				try {
					mPlayerService.pauseTrack();
					showCurrentlyPlaying();
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		currentlyPlayingText = (TextView) findViewById(R.id.CurrentlyPlayingText);
		currentlyPlayingText.setOnClickListener(new TextView.OnClickListener() {
			public void onClick(View v) {
				try {
					long article_id;
					article_id = mPlayerService.getId();
					launchEpisodeActivity(article_id);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		bindService(new Intent(this, PlayerService.class), mPlayerConnection, BIND_AUTO_CREATE);
		startService(new Intent(this, DownloadService.class));
		bindService(new Intent(this, DownloadService.class), mDownloadConnection, BIND_AUTO_CREATE);
		registerForContextMenu(getListView());
    }
    
    public void onRestart() {
        super.onRestart();
        showCurrentlyPlaying();
        updateDisplay();
    }

    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        RSSItem article = (RSSItem) this.getListAdapter().getItem(position);
        long article_id = article.id;
        launchEpisodeActivity(article_id);
    }

	int mark_listened = 0;
	int mark_new = 1;
	int download_eipsode = 2;
	int stop_download = 3;
	int delete_downloaded = 4;
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    	super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.episode_list_context_menu, menu);
    	for (int i = 0; i < menu.size(); i++) menu.getItem(i).setVisible(false);
        long id = ((AdapterView.AdapterContextMenuInfo) menuInfo).id;
        RSSDB db = new RSSDB(this);
        RSSItem article = db.getArticle(id);
        if (article.listened) {
        	menu.getItem(mark_new).setVisible(true);
        } else {
        	menu.getItem(mark_listened).setVisible(true);
        }
        if (article.downloadstate == RSSItem.downloadstates.UNDOWNLOADED) {
        	menu.getItem(download_eipsode).setVisible(true);
        }
        if (article.downloadstate == RSSItem.downloadstates.DOWNLOADING || article.downloadstate == RSSItem.downloadstates.QUEUED) {
        	menu.getItem(stop_download).setVisible(true);
        }
        if (article.downloadstate == RSSItem.downloadstates.DOWNLOADED || article.downloadstate == RSSItem.downloadstates.FAILED) {
        	menu.getItem(delete_downloaded).setVisible(true);
        }
    }

	public boolean onContextItemSelected(MenuItem item) {
		AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        RSSDB db = new RSSDB(this);
        RSSItem article = db.getArticle(info.id);
		ContentValues values = new ContentValues();
		switch (item.getItemId()) {
			case R.id.mark_listened:
				values.put("listened", true);
				db.updateArticle(info.id, values);
				break;
			case R.id.mark_new:
				values.put("listened", false);
				db.updateArticle(info.id, values);
				break;
			case R.id.download_episode:
	    		//mDownloadStatus.setText("Queuing download...");
	    		try {
					boolean result = mDownloadService.download(article.id);
					if (!result) Toast.makeText(EpisodeList.this, mDownloadService.getError(), Toast.LENGTH_LONG).show();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				break;
			case R.id.stop_download:
	    		try {
					boolean result = mDownloadService.stop_download(article.id);
					if (!result) Toast.makeText(EpisodeList.this, mDownloadService.getError(), Toast.LENGTH_LONG).show();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				break;
			case R.id.delete_downloaded:
	    		try {
					boolean result = mDownloadService.delete_download(article.id);
					if (!result) Toast.makeText(EpisodeList.this, mDownloadService.getError(), Toast.LENGTH_LONG).show();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				break;
			default:
				return super.onContextItemSelected(item);
		}
		updateDisplay();
		//mAdapter.updateRowView(article.id, mListView);
		return true;
	}

    private void launchEpisodeActivity(long article_id) {
        Intent ViewEpisodeIntent = new Intent(this, ViewEpisode.class);
        Builder builder = new Builder();
        String path = String.format("%d", article_id);
        builder.scheme("episode");
        builder.opaquePart(path);
        Uri uri = builder.build();
        ViewEpisodeIntent.setData(uri);
        startActivity(ViewEpisodeIntent);
    }
    
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.episode_list_menu, menu);
        return true;
    }

    public boolean onPrepareOptionsMenu(Menu menu) {
        // Show the 'show all' or 'show new' option, depending on state stored in preferences.
        MenuItem showAll = menu.getItem(2);
        MenuItem showNew = menu.getItem(3);
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        if (prefs.getBoolean("show_new", false)) {
        	showAll.setVisible(false);
        	showNew.setVisible(true);
        } else {
        	showAll.setVisible(true);
        	showNew.setVisible(false);
        }
    	return true;
    }
    
    /* Handles item selections */
    public boolean onOptionsItemSelected(MenuItem item) {
    	SharedPreferences.Editor editor;
    	SharedPreferences prefs;
        switch (item.getItemId()) {
        case R.id.update_feeds:
        	updateFeed();
            return true;
        case R.id.clear_feeds:
            RSSDB db = new RSSDB(this);
            db.clearDatabase();
            try {
					mDownloadService.clearDownloads();
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        updateDisplay();
            return true;
	    case R.id.show_all:
	        prefs = PreferenceManager.getDefaultSharedPreferences(this);
	        editor = prefs.edit();
	        editor.putBoolean("show_new", false);
	        editor.commit();
	        updateDisplay();
	        return true;
	    case R.id.show_new:
	        prefs = PreferenceManager.getDefaultSharedPreferences(this);
	        editor = prefs.edit();
	        editor.putBoolean("show_new", true);
	        editor.commit();
	        updateDisplay();
	        return true;
    	case R.id.about:
    		Dialog aboutDialog = new Dialog(this);
    		aboutDialog.setContentView(R.layout.sofastream_info);
    		aboutDialog.setTitle("About SofaStream");
    		aboutDialog.show();
    		return true;
	    case R.id.settings:
	        Intent SofaPrefsIntent = new Intent(this, SofaPrefs.class);
	        startActivity(SofaPrefsIntent);
	        return true;
	    }
        return false;
    }

    ProgressDialog pdialog;
    Handler mUpdateHandler = new Handler() {
		public void handleMessage(Message msg) {
			if (msg.what == 0) {
				//Starting a feed
				final String format = getResources().getString(R.string.update_dialog_title);
    	    	pdialog.setTitle(String.format(format, (String) msg.obj));
    	    	pdialog.setMessage(getResources().getString(R.string.refreshing_feeds));
			} else if (msg.what == 1) {
				//Parsed an episode
				pdialog.setMessage(String.format(getResources().getString(R.string.reading_episode), msg.arg1));
			} else if (msg.what == 2) {
    			//Finished a feed
			} else if (msg.what == 3) {
    			//Finished parsing
    			pdialog.dismiss();
    			updateDisplay();
			} else if (msg.what == 4) {
    			//Finished parsing
				switch (msg.arg1) {
					case PlayerService.PREPARED:
						showCurrentlyPlaying();
						break;
					case PlayerService.COMPLETION:
						showCurrentlyPlaying();
						break;
				}
			} else if (msg.what == 5) {
				long id = (Long) msg.obj;
				if (msg.arg1 == DownloadService.DOWNLOADING) {
			        int first = mListView.getFirstVisiblePosition();
			        int count = mListView.getChildCount();
			        for (int i=0; i<count; i++) {
			            if (mAdapter.getItemId(first + i) == id) {
			            	View row = mListView.getChildAt(i);
			            	TextView status = (TextView) row.findViewById(R.id.EpisodeStatus);
			            	status.setText(String.format(getResources().getString(R.string.downloading_episode), msg.arg1));
			            }
			        }
				} else {
					mAdapter.updateRowView(id, mListView);
				}
			} else {
                super.handleMessage(msg);
			}
		}
		
	};

    private void updateFeed() {
     	RSSDB db = new RSSDB(this);
		List<RSSFeed> feeds = db.getActiveFeeds();

		if (feeds.size() == 0) {
			Toast.makeText(this, getResources().getString(R.string.no_feeds_selected), Toast.LENGTH_LONG).show();
			return;
		}
		
		pdialog = new ProgressDialog(this);
		final String format = getResources().getString(R.string.update_dialog_title);
    	pdialog.setTitle(String.format(format, "feeds"));
    	//TODO: We should be able to skip a feed and/or cancel the whole process 
    	//pdialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", mUpdateHandler.obtainMessage());
    	//pdialog.setButton(DialogInterface.BUTTON_NEUTRAL, "Skip", mUpdateHandler.obtainMessage());
    	pdialog.show();

    	updateThread u = new updateThread(this);
    	u.start();
    }
        
	private void updateDisplay() {
		int first = mListView.getFirstVisiblePosition();
		((RSSAdapter) getListAdapter()).update();
		onContentChanged();
		mListView.setSelectionFromTop(first, 0);
	}

   public final class updateThread extends Thread implements ItemNotified {
    	Context c;
    	int itemCount;
    	
    	public updateThread(Context context) {
    		c = context;
    	}
        public void run() {
        	Looper.prepare();
        	
         	RSSDB db = new RSSDB(c);
			List<RSSFeed> feeds = db.getActiveFeeds();
			for (RSSFeed feed : feeds) {
				itemCount = 0;

				RSSHandler handler = new RSSHandler(this);
			
				notifyHost(0, 0, feed.title);
			
				try {
					handler.storeArticles(c, feed);
				} catch (RSSHandlerError e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
        		
			notifyHost(3, 0, null);
			
        	//Looper.loop();
        }
        
        public void notifyItemDone() {
        	notifyHost(1, ++itemCount, null);
        }
        public void notifyFeedDone() {
        	notifyHost(2, 0, null);
        }
        
        public void notifyHost(int what, int arg1, Object obj) {
			Message m = mUpdateHandler.obtainMessage(what, arg1, 0, obj);
			mUpdateHandler.sendMessage(m);
        }
    }
}

